package com.zhou.bpm.service.impl;


import cn.hutool.core.util.IdUtil;
import com.zhou.bpm.domain.dto.ApproveRequestDto;
import com.zhou.bpm.domain.dto.InstanceRequestDto;
import com.zhou.bpm.entity.*;
import com.zhou.bpm.service.*;
import com.zhou.common.UserContext;
import com.zhou.test.entity.SystemUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import static com.zhou.bpm.enmu.InstanceStatusEnum.*;
import static com.zhou.bpm.enmu.NodeApproveType.PARALLEL_APPROVAL;
import static com.zhou.bpm.enmu.TaskAction.*;
import static com.zhou.bpm.enmu.TaskApproverStatus.*;
import static com.zhou.common.Constants.APPLY;
import static com.zhou.common.Constants.FINISH_NO;

/**
 * @Author: zhoujinchuan
 * @Description: TODO（请添加描述）
 * @CreateTime: 2023/10/25 14:13
 */
@Service
public class ProcessFlowServiceImpl implements IProcessFlowService {

    @Autowired
    private IBpmProcessService processService;

    @Autowired
    private IBpmNodeApproverService nodeApproverService;

    @Autowired
    private IBpmNodeService nodeService;

    @Autowired
    private IBpmInstanceService instanceService;

    @Autowired
    private IProcessFlowService processFlowServiceThis;

    @Autowired
    private IBpmTaskService taskService;

    @Autowired
    private IBpmTaskApproverService taskApproverService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BpmInstance createInstance(InstanceRequestDto instanceRequestDto, String instanceName) {
        //1. 创建流程实例
        String processCode = instanceRequestDto.getProcessCode();
        BpmProcess bpmProcess = processService.lambdaQuery().eq(BpmProcess::getProcessCode, processCode).one();
        Assert.notNull(bpmProcess, "流程信息不存在,请联系管理员进行配置");
        BpmInstance bpmInstance = new BpmInstance();
        bpmInstance.setProcessCode(processCode);
        bpmInstance.setProcessName(bpmProcess.getProcessName());
        //获取申请人后的审批节点
        BpmNode node = nodeService.getNode(processCode, 1);
        Assert.notNull(node, "流程不存在审批节点，请联系管理员配置");
        SystemUser user = UserContext.getUser();
        bpmInstance.setInstanceName(instanceName == null ? user.getNickName() + "的 " + bpmProcess.getProcessName() + " 申请" : instanceName);
        bpmInstance.setStatus(UNDER_APPROVAL.getCode());
        bpmInstance.setCurrentNodeCode(node.getNodeCode());
        bpmInstance.setCurrentNodeName(node.getNodeName());
        bpmInstance.setApplier(user.getId() + "");
        bpmInstance.setApplierName(user.getNickName());
        LocalDateTime now = LocalDateTime.now();
        bpmInstance.setCreateTime(now);
        bpmInstance.setUpdateTime(now);
        Assert.isTrue(instanceService.save(bpmInstance), "创建流程失败");
        //2. 生成任务信息
        // 2.1 生成申请人任务
        BpmTask bpmTask = new BpmTask();
        String taskId = IdUtil.fastSimpleUUID();
        bpmTask.setInstanceId(bpmInstance.getId());
        bpmTask.setProcessCode(processCode);
        bpmTask.setTaskId(taskId);
        bpmTask.setNodeCode(APPLY);
        bpmTask.setAction(PROCESS_INITIATION.getCode());
        bpmTask.setCreateTime(now);
        bpmTask.setUpdateTime(now);
        Assert.isTrue(taskService.save(bpmTask), "创建流程失败");
        BpmTaskApprover bpmTaskApprover = new BpmTaskApprover();
        bpmTaskApprover.setTaskId(bpmTask.getId());
        bpmTaskApprover.setUpdateTime(now);
        bpmTaskApprover.setApprovedCode(user.getId());
        bpmTaskApprover.setApprovedName(user.getNickName());
        bpmTaskApprover.setStatus(PASSED.getCode());
        bpmTaskApprover.setOpinion(user.getNickName() + "发起申请");
        Assert.isTrue(taskApproverService.save(bpmTaskApprover), "创建流程失败");
        // 2.2 生成待办任务
        processFlowServiceThis.createTask(bpmInstance.getId(), bpmInstance.getProcessCode(), bpmInstance.getCurrentNodeCode());
        return bpmInstance;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createTask(Integer instanceId, String processCode, String nodeCode) {
        BpmNode bpmNode = nodeService.lambdaQuery().eq(BpmNode::getNodeCode, nodeCode).eq(BpmNode::getProcessCode, processCode).one();
        List<BpmNodeApprover> nodeApproverList = nodeApproverService.lambdaQuery().eq(BpmNodeApprover::getNodeId, bpmNode.getId()).list();
        BpmTask bpmTask = new BpmTask();
        String taskId = IdUtil.fastSimpleUUID();
        bpmTask.setTaskId(taskId);
        bpmTask.setInstanceId(instanceId);
        LocalDateTime now = LocalDateTime.now();
        bpmTask.setProcessCode(processCode);
        bpmTask.setNodeCode(nodeCode);
        bpmTask.setAction(THE_DEFAULT_VALUE.getCode());
        bpmTask.setCreateTime(now);
        bpmTask.setUpdateTime(now);
        Assert.isTrue(taskService.save(bpmTask), "创建任务失败");
        List<BpmTaskApprover> bpmTaskApprovers = nodeApproverList.stream().map(e -> {
            BpmTaskApprover bpmTaskApprover = new BpmTaskApprover();
            bpmTaskApprover.setTaskId(bpmTask.getId());
            bpmTaskApprover.setApprovedCode(e.getMemberCode());
            bpmTaskApprover.setStatus(PENDING_PROCESSING.getCode());
            bpmTaskApprover.setApprovedName(e.getMemberName());
            return bpmTaskApprover;
        }).collect(Collectors.toList());
        taskApproverService.saveBatch(bpmTaskApprovers);
        return bpmTask.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BpmInstance createInstance(InstanceRequestDto instanceRequestDto) {
        return processFlowServiceThis.createInstance(instanceRequestDto, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer approveTask(ApproveRequestDto approveRequestDto) {
        String taskId = approveRequestDto.getTaskId();
        BpmTask bpmTask = taskService.getById(taskId);
        Assert.notNull(bpmTask, "审核任务不存在");
        BpmInstance instance = instanceService.getById(bpmTask.getInstanceId());
        Assert.notNull(instance, "流程不存在");
        Assert.isTrue(UNDER_APPROVAL.getCode().equals(instance.getStatus()), "流程不在审批状态");
        SystemUser approveUser = approveRequestDto.getApproveUser();
        Integer approverId = approveUser.getId();
        BpmTaskApprover bpmTaskApprover = taskApproverService.lambdaQuery()
                .eq(BpmTaskApprover::getTaskId, taskId)
                .eq(BpmTaskApprover::getApprovedCode, approverId)
                .eq(BpmTaskApprover::getStatus, PENDING_PROCESSING.getCode())
                .one();
        Assert.notNull(bpmTaskApprover, "当前审批没有属于你的审核任务");
        //获取下面要用的信息
        String action = approveRequestDto.getAction();
        LocalDateTime now = LocalDateTime.now();
        String opinion = approveRequestDto.getOpinion();
        String processCode = bpmTask.getProcessCode();
        Integer instanceId = bpmTask.getInstanceId();
        //获取当前node
        BpmNode bpmNode = nodeService.lambdaQuery().eq(BpmNode::getProcessCode, processCode).eq(BpmNode::getNodeCode, bpmTask.getNodeCode()).one();
        Assert.notNull(bpmNode, "当前节点信息不存在，请联系管理员");
        Integer newTaskId = null;
        BpmTaskApprover applayApprover = null;
        switch (action) {
            case "1":
                //审批通过
                bpmTaskApprover.setUpdateTime(now);
                bpmTaskApprover.setOpinion(opinion);
                bpmTaskApprover.setStatus(PASSED.getCode());
                bpmTaskApprover.setApprovedName(approveUser.getNickName());
                Assert.isTrue(taskApproverService.updateById(bpmTaskApprover), "审核失败");
                //判断是否会签审批
                List<BpmTaskApprover> list = taskApproverService.lambdaQuery()
                        .eq(BpmTaskApprover::getTaskId, taskId)
                        .eq(BpmTaskApprover::getStatus, PENDING_PROCESSING.getCode())
                        .list();
                if (PARALLEL_APPROVAL.getCode().equals(bpmNode.getApproveType())) {
                    //会签 并且 存在待处理的审批
                    if (!CollectionUtils.isEmpty(list)) {
                        return bpmNode.getOrderNum();
                    }
                } else {
                    //抢签
                    bpmTask.setActualApprover(approverId);
                    bpmTask.setActualApproverName(approveUser.getNickName());
                    if (!CollectionUtils.isEmpty(list)) {
                        for (BpmTaskApprover taskApprover : list) {
                            taskApprover.setStatus(OR_SIGN_THROUGH_DEFAULT.getCode());
                        }
                        Assert.isTrue(taskApproverService.updateBatchById(list), "审核失败");
                    }
                }
                bpmTask.setAction(APPROVED.getCode());
                bpmTask.setUpdateTime(now);
                Assert.isTrue(taskService.updateById(bpmTask), "审核失败");

                //判断是否有下一节点
                BpmNode node = nodeService.getNode(processCode, bpmNode.getOrderNum() + 1);
                if (node != null) {
                    processFlowServiceThis.createTask(instanceId, processCode, node.getNodeCode());
                    instance.setCurrentNodeCode(node.getNodeCode());
                    instance.setCurrentNodeName(node.getNodeName());
                    Assert.isTrue(instanceService.updateById(instance), "审核失败");
                    return node.getOrderNum();
                } else {
                    instance.setStatus(COMPLETED.getCode());
                    //设置默认流程结束
                    instance.setCurrentNodeCode(FINISH_NO);
                    instance.setCurrentNodeName(FINISH_NO);
                    Assert.isTrue(instanceService.updateById(instance), "审核失败");
                }
                return -1;
            case "2":
                //退回上一节点
                BpmNode preNode = nodeService.getNode(processCode, bpmNode.getOrderNum() - 1);
                Assert.notNull(preNode, "没有上一个节点无法打回");
                //更新审批任务，以及作废其他任务
                bpmTaskApprover.setUpdateTime(now);
                bpmTaskApprover.setOpinion(opinion);
                bpmTaskApprover.setStatus(CALL_BACK_TO_CANCEL.getCode());
                bpmTaskApprover.setApprovedName(approveUser.getNickName());
                Assert.isTrue(taskApproverService.updateById(bpmTaskApprover), "审核失败");
                taskApproverService.lambdaUpdate()
                        .eq(BpmTaskApprover::getTaskId, taskId)
                        .ne(BpmTaskApprover::getStatus, CALL_BACK_TO_CANCEL.getCode())
                        .set(BpmTaskApprover::getStatus, OR_SIGN_THROUGH_DEFAULT.getCode())
                        .set(BpmTaskApprover::getUpdateTime, now).update();
                bpmTask.setAction(RETURN_TO_PREVIOUS_NODE.getCode());
                bpmTask.setUpdateTime(LocalDateTime.now());
                bpmTask.setActualApprover(approveUser.getId());
                bpmTask.setActualApproverName(approveUser.getNickName());
                Assert.isTrue(taskService.updateById(bpmTask), "审核失败");
                newTaskId = processFlowServiceThis.createTask(instanceId, processCode, preNode.getNodeCode());

                if (preNode.getOrderNum() == 0) {
                    //生成申请人审批信息
                    applayApprover = new BpmTaskApprover();
                    applayApprover.setApprovedCode(Integer.parseInt(instance.getApplier()));
                    applayApprover.setApprovedName(instance.getApplierName());
                    applayApprover.setTaskId(newTaskId);
                    applayApprover.setStatus(PENDING_PROCESSING.getCode());
                    taskApproverService.save(applayApprover);
                }
                instance.setCurrentNodeName(preNode.getNodeName());
                instance.setCurrentNodeCode(preNode.getNodeCode());
                Assert.isTrue(instanceService.updateById(instance), "审核失败");
                return preNode.getOrderNum();
            case "3":
                //退回申请人节点
                BpmNode applyNode = nodeService.getNode(processCode, 0);
                bpmTask.setAction(RETURN_TO_APPLICANT_NODE.getCode());
                bpmTask.setUpdateTime(LocalDateTime.now());

                bpmTask.setActualApprover(approveUser.getId());
                bpmTask.setActualApproverName(approveUser.getNickName());
                Assert.isTrue(taskService.updateById(bpmTask), "审核失败");
                //更新审批任务，以及作废其他任务
                bpmTaskApprover.setUpdateTime(now);
                bpmTaskApprover.setOpinion(opinion);
                bpmTaskApprover.setStatus(CALL_BACK_TO_CANCEL.getCode());
                bpmTaskApprover.setApprovedName(approveUser.getNickName());
                Assert.isTrue(taskApproverService.updateById(bpmTaskApprover), "审核失败");
                taskApproverService.lambdaUpdate()
                        .eq(BpmTaskApprover::getTaskId, taskId)
                        .ne(BpmTaskApprover::getStatus, CALL_BACK_TO_CANCEL.getCode())
                        .set(BpmTaskApprover::getStatus, OR_SIGN_THROUGH_DEFAULT.getCode())
                        .set(BpmTaskApprover::getUpdateTime, now).update();
                newTaskId = processFlowServiceThis.createTask(instanceId, processCode, applyNode.getNodeCode());
                //生成申请人审批信息
                applayApprover = new BpmTaskApprover();
                applayApprover.setApprovedCode(Integer.parseInt(instance.getApplier()));
                applayApprover.setApprovedName(instance.getApplierName());
                applayApprover.setTaskId(newTaskId);
                applayApprover.setStatus(PENDING_PROCESSING.getCode());
                taskApproverService.save(applayApprover);

                instance.setCurrentNodeName(applyNode.getNodeName());
                instance.setCurrentNodeCode(applyNode.getNodeCode());
                Assert.isTrue(instanceService.updateById(instance), "审核失败");
                return applyNode.getOrderNum();
            case "4":
                //路由任意节点
                BpmNode anyNode = nodeService.lambdaQuery().eq(BpmNode::getProcessCode, processCode).eq(BpmNode::getNodeCode, approveRequestDto.getNodeCode()).one();
                Assert.notNull(anyNode, "路由到的节点不存在");
                Assert.isTrue(bpmNode.getOrderNum() > anyNode.getOrderNum(), "不能路由到之后的任意节点");
                //更新审批任务，以及作废其他任务
                bpmTaskApprover.setUpdateTime(now);
                bpmTaskApprover.setOpinion(opinion);
                bpmTaskApprover.setStatus(CALL_BACK_TO_CANCEL.getCode());
                Assert.isTrue(taskApproverService.updateById(bpmTaskApprover), "审核失败");
                taskApproverService.lambdaUpdate()
                        .eq(BpmTaskApprover::getTaskId, taskId)
                        .ne(BpmTaskApprover::getStatus, CALL_BACK_TO_CANCEL.getCode())
                        .set(BpmTaskApprover::getStatus, OR_SIGN_THROUGH_DEFAULT.getCode())
                        .set(BpmTaskApprover::getUpdateTime, now).update();
                bpmTask.setAction(ROUTE_ANY_NODE.getCode());
                bpmTask.setUpdateTime(LocalDateTime.now());
                bpmTask.setActualApprover(approveUser.getId());
                bpmTask.setActualApproverName(approveUser.getNickName());
                Assert.isTrue(taskService.updateById(bpmTask), "审核失败");
                processFlowServiceThis.createTask(instanceId, processCode, anyNode.getNodeCode());
                if (anyNode.getOrderNum() == 0) {
                    //生成申请人审批信息
                    applayApprover = new BpmTaskApprover();
                    applayApprover.setApprovedCode(Integer.parseInt(instance.getApplier()));
                    applayApprover.setApprovedName(instance.getApplierName());
                    applayApprover.setTaskId(newTaskId);
                    applayApprover.setStatus(PENDING_PROCESSING.getCode());
                    taskApproverService.save(applayApprover);
                }
                instance.setCurrentNodeName(anyNode.getNodeName());
                instance.setCurrentNodeCode(anyNode.getNodeCode());
                Assert.isTrue(instanceService.updateById(instance), "审核失败");
                return anyNode.getOrderNum();
            case "5":
                //申请人撤回
                Assert.isTrue(APPLY.equals(bpmNode.getNodeCode()), "不在申请人节点不能撤回");
                bpmTask.setAction(ORIGINATOR_WITHDRAWAL.getCode());
                bpmTask.setUpdateTime(LocalDateTime.now());
                Assert.isTrue(taskService.updateById(bpmTask), "审核失败");
                bpmTaskApprover.setUpdateTime(now);
                bpmTaskApprover.setOpinion(opinion);
                bpmTaskApprover.setStatus(CALL_BACK_TO_CANCEL.getCode());
                Assert.isTrue(taskApproverService.updateById(bpmTaskApprover), "审核失败");
                //设置默认流程结束
                instance.setCurrentNodeCode(FINISH_NO);
                instance.setCurrentNodeName(FINISH_NO);
                instance.setStatus(WITHDRAWN.getCode());
                Assert.isTrue(instanceService.updateById(instance), "审核失败");
                return -1;
            default:
                throw new IllegalArgumentException("审批动作有误");
        }
    }


}
